package cn.wolfcode.business.service.impl;

import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

import cn.wolfcode.business.domain.BpmnInfo;
import cn.wolfcode.business.domain.ServiceItem;
import cn.wolfcode.business.mapper.BpmnInfoMapper;
import cn.wolfcode.business.mapper.ServiceItemMapper;
import cn.wolfcode.business.service.IServiceItemService;
import cn.wolfcode.business.vo.HistoryVO;
import cn.wolfcode.business.vo.PackageAuditVO;
import cn.wolfcode.common.exception.ServiceException;
import cn.wolfcode.common.utils.DateUtils;
import cn.wolfcode.common.utils.PageUtils;
import cn.wolfcode.common.utils.SecurityUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.wolfcode.business.mapper.CarPackageAuditMapper;
import cn.wolfcode.business.domain.CarPackageAudit;
import cn.wolfcode.business.service.ICarPackageAuditService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 套餐信息Service业务层处理
 * 
 * @author dafei
 * @date 2023-11-03
 */
@Service
@Transactional
public class CarPackageAuditServiceImpl implements ICarPackageAuditService 
{
    @Autowired
    private CarPackageAuditMapper carPackageAuditMapper;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private BpmnInfoMapper bpmnInfoMapper;

    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private ServiceItemMapper serviceItemMapper;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;



    /**
     * 查询套餐信息
     * 
     * @param id 套餐信息主键
     * @return 套餐信息
     */
    @Override
    public CarPackageAudit selectCarPackageAuditById(Long id)
    {
        return carPackageAuditMapper.selectCarPackageAuditById(id);
    }

    /**
     * 查询套餐信息列表
     * 
     * @param carPackageAudit 套餐信息
     * @return 套餐信息
     */
    @Override
    public List<CarPackageAudit> selectCarPackageAuditList(CarPackageAudit carPackageAudit)
    {
        return carPackageAuditMapper.selectCarPackageAuditList(carPackageAudit);
    }

    /**
     * 新增套餐信息
     * 
     * @param carPackageAudit 套餐信息
     * @return 结果
     */
    @Override
    public int insertCarPackageAudit(CarPackageAudit carPackageAudit)
    {
        carPackageAudit.setCreateTime(DateUtils.getNowDate());
        return carPackageAuditMapper.insertCarPackageAudit(carPackageAudit);
    }

    /**
     * 修改套餐信息
     * 
     * @param carPackageAudit 套餐信息
     * @return 结果
     */
    @Override
    public int updateCarPackageAudit(CarPackageAudit carPackageAudit)
    {
        return carPackageAuditMapper.updateCarPackageAudit(carPackageAudit);
    }

    /**
     * 批量删除套餐信息
     * 
     * @param ids 需要删除的套餐信息主键
     * @return 结果
     */
    @Override
    public int deleteCarPackageAuditByIds(Long[] ids)
    {
        return carPackageAuditMapper.deleteCarPackageAuditByIds(ids);
    }

    /**
     * 删除套餐信息信息
     * 
     * @param id 套餐信息主键
     * @return 结果
     */
    @Override
    public int deleteCarPackageAuditById(Long id)
    {
        return carPackageAuditMapper.deleteCarPackageAuditById(id);
    }

    @Override
    public InputStream getProcessImg(Long id) {
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(bpmnInfo.getVersion())  //指定版本
                .singleResult();//???

        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(id);
        List<String> activeActivityIds = new ArrayList<>();
        if(audit.getStatus().equals(CarPackageAudit.STATUS_IN_ROGRESS)){
            //高亮显示当前流程所在节点-坐标
            activeActivityIds = runtimeService.getActiveActivityIds(audit.getInstanceId());
        }else{
            activeActivityIds = Collections.emptyList();
        }
        //图片
        DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        /**
         * 第一个参数: 流程定义模型
         * 第二个参数: 高亮节点集合---当前流程推进到哪个节点了---传的是节点坐标
         * 第三个参数: 高亮连线集合
         */
        InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                activeActivityIds,
                Collections.emptyList(),
                "宋体",
                "宋体",
                "宋体");
        return inputStream;
    }

    @Override
    public void auditCancel(Long id) {
        //参数校验
        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(id);
        if(audit == null){
            throw new ServiceException("参数异常");
        }
        if(!CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus())){
            throw new ServiceException("只有在审核中状态才允许撤销操作");
        }
        //服务套餐--状态-初始化
        ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(audit.getServiceItemId());
        serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_INIT);
        serviceItemMapper.updateServiceItem(serviceItem);

        //审核信息记录--状态--撤销
        audit.setStatus(CarPackageAudit.STATUS_CANCEL);
        carPackageAuditMapper.updateCarPackageAudit(audit);

        //流程--流程结束--删除
        runtimeService.deleteProcessInstance(audit.getInstanceId(), "审核被撤销了");
    }

    @Override
    public List<HistoryVO> queryHistory(Long instanceId) {

        if(instanceId == null){
            throw new ServiceException("参数异常");
        }
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);

        //原生的activit7返回domain对象 不一定满足页面的要求, 所以:一般将元素activiti对象进行二次加工
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(instanceId.toString())  //
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())  //套餐审核节点
                .finished()  //要求节点执行审核操作
                .list();

        //思考: 怎么查询历史??
        List<HistoryVO> vos = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (HistoricTaskInstance task : list) {
            HistoryVO vo = new HistoryVO();
            vo.setTaskName(task.getName());
            // 将Date类型转成对应格式的String
            vo.setEndTime(sdf.format(task.getEndTime()));
            vo.setStartTime(sdf.format(task.getStartTime()));
            //间隔时间: 花费时间:  endTime-startTime
            // 格式是 毫秒 ---> xx年 xx天 xxx月xxx日 xx时
            vo.setDurationInMillis(task.getDurationInMillis() / 1000 + "s");
            //审核备注
            //查询节点审核备注信息?
            //由于可能存在并行网关，有多条审核备注，所以要拼接在一起
            List<Comment> comments = taskService.getTaskComments(task.getId());
            if(comments != null || comments.size() > 0){
                StringBuilder sb = new StringBuilder(80);
                for (Comment comment : comments) {
                    //节点备注信息
                    sb.append(comment.getFullMessage());
                }
                vo.setComment(sb.toString());
            }
            vos.add(vo);
        }
        return vos;
    }

    @Override
    public List<CarPackageAudit> todoQuery(CarPackageAudit carPackageAudit) {
        //查询当前审核人 == 当前登录用户对象
        //思考:
        //1L: 审核信息列表与待办信息列表是一样的, 意味着最终查询主干表一样: car_package_audit
        //2: 观察发现car_package_audit 存在一列: intanceId--流程实例id---这个流程id是否可能跟当前登录用户对象id扯上关系???
        //3: 分析发现, 可以通过流程实例获取所有流程实例上的 任务节点, 而任务节点上都绑定负责人(用户id)
        //4: 此时就可以, 使用这个负责人 这个列与 当前登录用户对象id 建立联系
        //5:  已知: userId---->CarPackageAudit[intance_id]----ProecessInstance---->Task[task负责人id]---->--->求: List<CarPackageAudit>
        //逻辑:
        // 1>查询当前登录用户名下有多个需要审核的task
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee(SecurityUtils.getUserId().toString())
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .list();
        // 2>遍历这些task 获取这些task 绑定的 流程实例id
        if(list  == null || list.size() == 0){
            return null;
        }
        List<String> ids = new ArrayList<>();
        for (Task task : list) {
            ids.add(task.getProcessInstanceId());
        }
        // 3>遍历查询流程实例id, 以它们为条件查询这些实例绑定的: 流程审核信息:  List<CarPackageAudit>
        PageUtils.startPage();  //分页
        return carPackageAuditMapper.selectByInstanceIds(ids);
    }

    @Override
    public List<CarPackageAudit> doneQuery(CarPackageAudit carPackageAudit) {
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectLastByType(CarPackageAudit.FLOW_AUDIT_TYPE);
        //查询历史task
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .taskAssignee(SecurityUtils.getUserId().toString())
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .list();
        // 2>遍历这些task 获取这些task 绑定的 流程实例id
        if(list  == null || list.size() == 0){
            return null;
        }
        List<String> ids = new ArrayList<>();
        for (HistoricTaskInstance task : list) {
            ids.add(task.getProcessInstanceId());
        }
        // 3>遍历查询流程实例id, 以它们为条件查询这些实例绑定的: 流程审核信息:  List<CarPackageAudit>
        PageUtils.startPage();  //分页
        return carPackageAuditMapper.selectByInstanceIds(ids);
    }

    @Override
    public void audit(PackageAuditVO vo) {

        //审核条件
        //id != null
        //状态 为审核中
        if(vo == null){
            throw new ServiceException("参数异常");
        }
        CarPackageAudit audit = carPackageAuditMapper.selectCarPackageAuditById(vo.getId());
        if(audit == null || !CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus())){
            throw new ServiceException("参数异常或者状态异常");
        }
        //流程推进: 节点审核
        //查询任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(audit.getInstanceId())
                .singleResult();
        if(task == null){
            return;
        }
        //审核备注
        String message = "";
        if(CarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus())){
            //通过
            message = "审批人:" + SecurityUtils.getUsername() + "通过, 审核备注:[" + vo.getAuditInfo() + "]";
        }else{
            //拒绝
            message = "审批人:" + SecurityUtils.getUsername() + "拒绝, 审核备注:[" + vo.getAuditInfo() + "]";
        }
        taskService.addComment(task.getId(), audit.getInstanceId().toString(), message);

        Map<String, Object> map = new HashMap<>();
        map.put("shopOwner", CarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus()));
        //处理
        taskService.complete(task.getId(), map);


        ServiceItem serviceItem = serviceItemMapper.selectServiceItemById(audit.getServiceItemId());

        //业务线推进
        if(CarPackageAudit.STATUS_PASS.equals(vo.getAuditStatus())){
            //审核通过
            Task nextTask = taskService.createTaskQuery()
                    .processInstanceId(audit.getInstanceId())
                    .singleResult();
            //判断是否有下一个节点
            if(nextTask == null){
                //  没有: 当前流程正常结束
                //       1:服务套餐--审核通过
                serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_APPROVED);
                serviceItemMapper.updateServiceItem(serviceItem);
                //       2:审核流程信息--审核通过
                audit.setStatus(CarPackageAudit.STATUS_PASS);
                carPackageAuditMapper.updateCarPackageAudit(audit);
            }
            //有: 当前流程还在继续 -- 啥都不做
        }else {
            //审核拒绝
            //1:服务套餐--审核拒绝
            serviceItem.setAuditStatus(ServiceItem.AUDITSTATUS_REPLY);
            serviceItemMapper.updateServiceItem(serviceItem);
            //2:审核流程信息--审核拒绝
            audit.setStatus(CarPackageAudit.STATUS_REJECT);
            carPackageAuditMapper.updateCarPackageAudit(audit);
            //3:流程--流程正常结束
        }
    }
}
